﻿#include "adsocket.h"
#include <QDebug>
#pragma execution_character_set("utf-8")
extern QMap<QString,QImage> qMapPicturePath;// 图片路径

// QTcpSocket会自动处理大小端问题
AdSocket::AdSocket(QObject *parent) :
    QTcpSocket(parent)
{
    //注册tcp_MSG类型
    qRegisterMetaType<tcp_MSG>("tcp_MSG");

    id = "0011";
    qDebug()<<"程序使用端口:"<<QAbstractSocket::localPort();
    /* 每当有新的输入数据时，就会发出这个信号。
    请记住，新传入的数据只报告一次;如果您不读取所有数据，这个类会缓冲数据，您可以稍后读取它，但是除非新数据到达，否则不会发出信号。*/
    connect(this, SIGNAL(readyRead()),this, SLOT(readMsg()));

    //该信号在调用connectToHost()并成功建立连接之后发出。
    connect(this, SIGNAL(connected()),this, SLOT(conSuc()));

    // 该信号在套接字断开连接时发出
    connect(this, SIGNAL(disconnected()),this, SLOT(conAgain()));

    address="127.0.0.1";
    port=8888;

    connectToHost(QHostAddress(address), port);// 默认连接127.0.0.1 8888

    //该信号在错误发生后发出。socketError参数描述发生错误的类型
    connect(this, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(conAgain(QAbstractSocket::SocketError)));

    readMsgType=MsgType::Init;

    milsec=0;
}

AdSocket::~AdSocket()
{

}

// 接收信息
void AdSocket::readMsg()
{
    //读取缓冲区数据
    QByteArray  buffer = readAll();
    qDebug()<<"进来了"<<__LINE__;
    if(readMsgType==MsgType::Init)
    {
        tcp_MSG *msg=(tcp_MSG *)buffer.data();        //强转为结构体，需要用结构体指针接收
        qDebug()<<"进来了"<<__LINE__;
        qDebug()<<"类型"<<msg->type;
        switch (msg->type)
        {
        case WEATHER://天气
        {
            QString city=msg->city;
            QString area=msg->area;
            QString weather=msg->weather;
            //weather="\t\t"+city+"\t"+area+"\n"+weather;
            emit sig_showWeather(city,area,weather);// 发送天气信息
            break;
        }
        case MASSEGE:// 留言
        {
            QString tcp_Txt=msg->txt;
            qDebug()<<"文字信息："<<tcp_Txt;
            emit sig_showTxt(tcp_Txt);// 发送文字信息
            break;
        }
        case VIDEO:// 视频
            qDebug()<<"发送视频信息：";
            break;
        case AD_add://添加广告
        {
            qDebug()<<"添加广告"<<__LINE__;
            qDebug()<<"文件名"<< QString(msg->fileName);
            qDebug()<<"编号"<< msg->index;
            qDebug()<<"总数"<< msg->allAd_Num;

            needFileSize=msg->fileSize;
            currentReceiveSize=0;
            currentReceiveByte.clear();
            QByteArray  sendTcpData;
            //使用字节数组,将结构体转为字符数组，发送的是字符数组（数据在传输过程中都是byte类型的）
            //直接sizeof（senddata）内存会变小，设置了对齐方式解决
            sendTcpData.resize(sizeof(tcp_backMSG));
            tcp_backMSG backMsg={};
            strcpy(backMsg.id,id.toUtf8().data());
            backMsg.state=1;
            backMsg.type=MsgType::Write_back;
            //将封装好的结构体转为QByteArray数组，因为传输都是Byte类型
            memcpy(sendTcpData.data(),&backMsg,sizeof(tcp_backMSG));

            this->write(sendTcpData);// 回复

            fileName.clear();
            fileName=QString(msg->fileName);

            readMsgType=MsgType::AD_add;
            break;
        }
        case AD_delete://删除广告
        {
            qDebug()<<"删除广告"<<__LINE__;
            qDebug()<<"文件名"<< QString(msg->fileName);
            int  success= qMapPicturePath.remove(QString(msg->fileName));
            if(success)
            {
                if(qMapPicturePath.count()>=1)
                {// 有图片
                    emit sig_showImage(qMapPicturePath.first());
                }
                else
                {// 没有图片
                    QImage image(100, 100, QImage::Format_RGBA8888);
                    image.fill(QColor(0, 0, 0, 0));// 纯透明图片
                    emit sig_showImage(image);
                }
                emit GUI_WarningSignal("提示","删除广告成功",NULL,NULL);
            }
            else
            {
                emit GUI_WarningSignal("提示","删除广告失败",NULL,NULL);
            }
            break;
        }
        default:
            qDebug()<<"";
            break;
        }
    }
    else if(readMsgType==MsgType::AD_add)
    {
        qDebug()<<"添加广告"<<__LINE__;
        qDebug()<<"需要接收大小："<<needFileSize;
        // 记录开始时间
        QTime startTime = QTime::currentTime();

        currentReceiveSize+=buffer.size();
        currentReceiveByte+=buffer;
        qDebug()<<"当前接收大小："<<currentReceiveSize;
        emit sig_showProgressBar(currentReceiveSize,needFileSize);
        // 记录结束时间
        QTime endTime = QTime::currentTime();
        // 计算运行时间
        milsec += startTime.msecsTo(endTime);

        if(needFileSize==currentReceiveSize)
        {
            qDebug()<<"图片接收完成";
            startTime = QTime::currentTime();

            QByteArray Ret_bytearray = QByteArray::fromBase64(currentReceiveByte);
            QBuffer buffer(&Ret_bytearray);
            buffer.open(QIODevice::WriteOnly);
            QPixmap imageresult;
            imageresult.loadFromData(Ret_bytearray);

            qMapPicturePath.insert(fileName,imageresult.toImage());// 先插入键值
            emit sig_showImage(imageresult.toImage());

            readMsgType=MsgType::Init;

            endTime = QTime::currentTime();
            milsec += startTime.msecsTo(endTime);
            qDebug()<<"接收消耗时间"<<milsec<<"毫秒";
        }
    }
}
// 成功建立连接
void AdSocket::conSuc()
{
    QByteArray  sendTcpData;
    //使用字节数组,将结构体转为字符数组，发送的是字符数组（数据在传输过程中都是byte类型的）
    //直接sizeof（senddata）内存会变小，设置了对齐方式解决
    sendTcpData.resize(sizeof(tcp_backMSG));
    tcp_backMSG msg={};
    strcpy(msg.id,id.toUtf8().data());
    msg.state=0;
    msg.type=MsgType::Init;
    //将封装好的结构体转为QByteArray数组，因为传输都是Byte类型
    memcpy(sendTcpData.data(),&msg,sizeof(tcp_backMSG));

    this->write(sendTcpData);
    qDebug()<<"connect success";
}

// 重新连接
void AdSocket::conAgain()
{
    qDebug()<<"套接字断开连接时重新连接";
    abort();// 终止当前连接并重置套接字
    connectToHost(QHostAddress(address), port);
}
// 重新连接
void AdSocket::conAgain(QAbstractSocket::SocketError error)
{
    qDebug()<<"连接失败:"<<error;
    readMsgType=MsgType::Init;

    if(error==QAbstractSocket::ConnectionRefusedError)
    {
        abort();// 终止当前连接并重置套接字
        connectToHost(QHostAddress(address), port);
    }
}

